﻿#include "Window.h"

#define ClassName "day day up"

Window::Window(INT width, INT height, LPCSTR WindowName)
	:
	hInstance(GetModuleHandle(NULL)),
	width(width),
	height(height)
{
	// 1.定义窗口类
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(wcex);//指定结构体的大小
	wcex.style = CS_CLASSDC;//结构体的大小，‌用于版本控制。‌
	wcex.lpfnWndProc = HandleMsgSetup;//指向窗口过程的指针，‌处理窗口的各种消息。‌
	wcex.cbClsExtra = 0;//窗口类附加内存的大小，‌通常设为0。‌
	wcex.cbWndExtra = 0;//窗口附加内存的大小，‌通常设为0。‌
	wcex.hInstance = hInstance;//应用程序实例句柄
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);//窗口类的光标句柄
	wcex.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0, 0, 0));//窗口背景画刷句柄
	wcex.lpszMenuName = nullptr;//窗口类的菜单
	wcex.lpszClassName = ClassName;//窗口类名
	wcex.hIcon = nullptr;//类图标的句柄
	wcex.hIconSm = nullptr;//小图标的句柄

	// 2.注册窗口类
	RegisterClassEx(&wcex);//注册本地窗口

	RECT rect;
	rect.left = rect.top = 0;
	rect.right = width;
	rect.bottom = height;
	AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);//根据所需的客户端矩形大小计算窗口矩形的所需大小

	INT cx = GetSystemMetrics(SM_CXSCREEN);
	INT cy = GetSystemMetrics(SM_CYSCREEN);
	// 3.创建窗口
	HWND hWnd = CreateWindowEx(
		0,//扩展窗口样式
		ClassName,//窗口类名或窗口类原子的指针
		WindowName,//窗口名
		WS_OVERLAPPEDWINDOW,//窗口样式
		cx / 2 - width / 2,//显示窗口位置
		cy / 2 - height / 2,
		rect.right - rect.left,//创建窗口大小
		rect.bottom - rect.top,
		HWND_DESKTOP,//没有父窗口
		nullptr,//菜单句柄或子窗口ID
		hInstance,//应用程序实例句柄
		this//指向窗口创建数据的指针
	);

	if (nullptr == hWnd)
		throw std::runtime_error("hWnd is nullptr");
	// 4.显示窗口
	ShowWindow(hWnd, SW_SHOW);//设置指定窗口的显示状态
	UpdateWindow(hWnd);

	_graphic = std::make_unique<Graphic>(hWnd, width, height);
}

Window::~Window() 
{
	UnregisterClass(ClassName, hInstance);
}

BOOL Window::Message() noexcept
{
	MSG msg{ 0 };
	while (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) 
	{
		// 窗口退出信息
		if (msg.message == WM_QUIT)
		{
			return FALSE;
		}
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return TRUE;
}

Graphic& Window::GetGraphic()
{
	return *_graphic;
}

LRESULT Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{
	if (WM_NCCREATE == msg)
	{
		CREATESTRUCTW* pCreate = (CREATESTRUCTW*)lParam;
		Window* pWnd = (Window*)pCreate->lpCreateParams;
		SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pWnd);
		SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)&HandleMsgThunk);
		return pWnd->HandleMsg(hWnd, msg, wParam, lParam);
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

LRESULT Window::HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{	
	Window* pWnd = (Window*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
	return pWnd->HandleMsg(hWnd, msg, wParam, lParam);
}

LRESULT Window::HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept
{
	switch (msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_KEYUP:
		switch (wParam)
		{
		case VK_F1:
			SetWindowText(hWnd, "VK_F1");
			break;
		case VK_F2:
			SetWindowText(hWnd, "VK_F2");
			break;
		default:
			break;
		}
		break;
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}
